package net.kengo.volleyball.scheduler;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import net.kengo.volleyball.scheduler.data.GameDay;
import net.kengo.volleyball.scheduler.data.Match;
import net.kengo.volleyball.scheduler.data.Scheduler;
import net.kengo.volleyball.scheduler.data.Week;


public class ScheduleParser
{
   private static final String CLASSNAME = ScheduleParser.class.getName();
   private static final Logger logger    = Logger.getLogger(CLASSNAME);
   
   private final int         year      = 2012;

   private String            location  = "http://www.motown.lmco.com/~mra/volley/sched12.txt";
   private String            teamNum   = new String();

   private BufferedReader    reader    = null;

   private GregorianCalendar currDate  = new GregorianCalendar();
   private int               currWeek  = 1;
   private Scheduler         scheduler = new Scheduler();


   private ScheduleParser()
   {
      // Never call this
   }


   public ScheduleParser( String teamNum )
   {
      this( null, teamNum );
   }


   public ScheduleParser( String location, String teamNum )
   {
      if ( location != null )
      {
         this.location = location;
      }

      setTeamNumber(teamNum);

      openConnection();

      //System.out.println( scheduler );
   }


   private void setTeamNumber( String teamNum )
   {
      this.teamNum = teamNum;
   }


   private void openConnection()
   {
      InputStream inputStream = null;

      try
      {
         // Set the input stream to the url
         URL url = new URL( this.location );
         inputStream = url.openStream();
      }
      catch(Exception e)
      {
         File file = new File(this.location);
         try
         {
            inputStream = new FileInputStream(file);
         }
         catch( FileNotFoundException exception )
         {
            logger.log( Level.SEVERE, "File not found:  " + file.getAbsolutePath(), exception );
            inputStream = null;
         }
      }

      if( inputStream != null ) {
         reader = new BufferedReader( new InputStreamReader(inputStream) );
      }
}


   public void parseSchedule()
   {
      parseScheduleHeader();
      parseScheduleBody();
   }


   private String getNextLine()
   {
      String line = null;

      try
      {
         line = reader.readLine();
      }
      catch( IOException e )
      {
         System.err.println( e );
      }

      return line;
   }


   private void parseScheduleHeader()
   {
      String line = null;

      boolean endOfHeader = false;
      while ( !endOfHeader )
      {
         line = getNextLine();
         if ( ( line == null ) || 
              ( line.startsWith("-----") ) )
         {
            endOfHeader = true;
            break;
         }
      }
   }


   private void parseScheduleBody()
   {
      String line1 = null;
      String line2 = null;

      boolean endOfSchedule = false;
      while ( !endOfSchedule )
      {
         // Get the first line of the week
         line1 = getNextLine();
         if ( ( line1 == null ) || 
              ( line1.startsWith("</PRE>") ) ||
              ( line1.startsWith("</pre>") ) )
         {
            endOfSchedule = true;
            break;
         }

         // Get the second line of the week
         line2 = getNextLine();
         if ( ( line2 == null ) || 
              ( line2.startsWith("</PRE>") ) ||
              ( line1.startsWith("</pre>") ) )
         {
            endOfSchedule = true;
            break;
         }

         // Skip the separator lines
         getNextLine();

         processWeek( line1, line2 );
      }
   }

   private void processWeek( String line1, String line2 )
   {
      //System.out.println( line1 + "\n" + line2 + "\n" );

      String token1 = null;
      String token2 = null;

      StringTokenizer tokenizer1 = new StringTokenizer( line1, "|", true);
      StringTokenizer tokenizer2 = new StringTokenizer( line2, "|", true);

      try
      {
         // Handle first column (Week# and Date)
         token1 = tokenizer1.nextToken();
         token2 = tokenizer2.nextToken();
         parseDate( token1 );
         //parseWeek( token1 );

         Week     week     = new Week( currWeek++ );
         GameDay  gameDay  = new GameDay( this.currDate );


         // Skip separator
         token1 = tokenizer1.nextToken();
         token2 = tokenizer2.nextToken();

         // Begin parsing the week's matches
         token1 = tokenizer1.nextToken();
         token2 = tokenizer2.nextToken();

         int courtNum = 1;
         while ( tokenizer1.hasMoreTokens() && tokenizer2.hasMoreTokens() )
         {
            if ( token1.equals("|") && token2.equals("|") )
            {
               // Get the next tokens
               token1 = tokenizer1.nextToken();
               token2 = tokenizer2.nextToken();
               
               // If another bar, that signifies the next day
               if ( token1.equals("|") && token2.equals("|") )
               {
                  // Go to the next day
                  currDate.add( Calendar.DAY_OF_WEEK, 1 );
                  courtNum = 1;

                  if ( gameDay.getNumMatches() != 0 )
                  {
                     week.add(gameDay);
                  }

                  gameDay = new GameDay( this.currDate );

                  // Get the next tokens
                  token1 = tokenizer1.nextToken();
                  token2 = tokenizer2.nextToken();
               }
               else
               {
                  // Go to the next court
                  courtNum++;
               }
            }
            else
            {
               // Handle matches
               Match match = processMatch(token1);
               if ( match != null )
               {
                  match.setCourtNum( courtNum );

                  gameDay.addMatch(1, match );
               }

               match = processMatch(token2);
               if ( match != null )
               {
                  match.setCourtNum( courtNum );

                  gameDay.addMatch(2, match );
               }

               // Get the next tokens
               token1 = tokenizer1.nextToken();
               token2 = tokenizer2.nextToken();
            }
         }

         if ( gameDay.getNumMatches() != 0 )
         {
            week.add(gameDay);
         }

         scheduler.add(week);
      }
      catch( StringIndexOutOfBoundsException siobe )
      {
         // Ignore these exceptions
      }
      catch ( Exception e )
      {
         System.err.println(e);
      }
   }

   private Match processMatch( String currMatch )
   {
      Match match = null;

      int midIndex = currMatch.indexOf("-");
      int endIndex = currMatch.length();

      if ( ( midIndex > 0 ) && ( midIndex != endIndex ) )
      {
         String team1 = currMatch.substring(0, midIndex).trim();
         String team2 = currMatch.substring(midIndex+1, endIndex).trim();

         if( team1.equals(this.teamNum) )
         {
            match = new Match(team2);
         }
         else if( team2.equals(this.teamNum) )
         {
            match = new Match(team1);
         }
      }

      return match;
   }


   private void parseDate( String token )
   {
      SimpleDateFormat df = new SimpleDateFormat( "M/dd" );
      try
      {
         currDate.setTime( df.parse(token) );
         currDate.set( Calendar.YEAR, this.year );
      }
      catch ( ParseException e )
      {
         //Logger.getLogger(ScheduleParser.class.getName()).severe("Unparsable date:  " + token );
      }
   }


//   private void parseWeek( String token )
//   {
//      if ( token.startsWith("Week") )
//      {
//         String week = token.substring( 5, token.length() ).trim();
//         this.currWeek = Integer.parseInt( week );
//      }
//   }


   private void printDate()
   {
      System.out.println( currDate.get(Calendar.MONTH) + "/" + 
                          currDate.get(Calendar.DAY_OF_MONTH) + "/" +
                          currDate.get(Calendar.YEAR) );
   }


   public String getHTML()
   {
      return scheduler.toString();
   }


   public static String usage()
   {
      String usage = new String( "ParseSchedule usage:\n" +
                                 "\tjava ParseSchedule [location] teamNum" );
      return usage;
   }


   public static void main( String args[] )
   {
      String teamNum  = "12";
      String location = null;

      int ii = 0;
      switch( args.length )
      {
         case 2:
            location = args[ii++];
            // pass through to case 1

         case 1:
            teamNum = args[ii++];
            break;

         case 0:
            // Do nothing.  Use the default settings.
            break;

         default:
            System.out.println( ScheduleParser.usage() );
            System.exit(-1);
            break;
      }

      ScheduleParser parser = new ScheduleParser( location, teamNum );
      parser.parseSchedule();

      System.out.println( parser.toString() );

   }


}
